home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / linuxdoc-sgml-1.1 / sgmls-1.1 / sgmldecl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  42.9 KB  |  1,742 lines

  1. /* sgmldecl.c -
  2.    SGML declaration parsing.
  3.  
  4.    Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. #include "sgmlincl.h"
  8.  
  9. /* Symbolic names for the error numbers that are be generated only by
  10. this module. */
  11.  
  12. #define E_STANDARD 163
  13. #define E_SIGNIFICANT 164
  14. #define E_BADLIT 165
  15. #define E_SCOPE 166
  16. #define E_XNUM 167
  17. #define E_BADVERSION 168
  18. #define E_NMUNSUP 169
  19. #define E_XNMLIT 170
  20. #define E_CHARDESC 171
  21. #define E_CHARDUP 172
  22. #define E_CHARRANGE 173
  23. #define E_7BIT 174
  24. #define E_CHARMISSING 175
  25. #define E_SHUNNED 176
  26. #define E_NONSGML 177
  27. #define E_CAPSET 178
  28. #define E_CAPMISSING 179
  29. #define E_SYNTAX 180
  30. #define E_CHARNUM 181
  31. #define E_SWITCHES 182
  32. #define E_INSTANCE 183
  33. #define E_ZEROFEATURE 184
  34. #define E_YESNO 185
  35. #define E_CAPACITY 186
  36. #define E_NOTSUPPORTED 187
  37. #define E_FORMAL 189
  38. #define E_BADCLASS 190
  39. #define E_MUSTBENON 191
  40. #define E_BADBASECHAR 199
  41. #define E_SYNREFUNUSED 200
  42. #define E_SYNREFUNDESC 201
  43. #define E_SYNREFUNKNOWN 202
  44. #define E_SYNREFUNKNOWNSET 203
  45. #define E_FUNDUP 204
  46. #define E_BADFUN 205
  47. #define E_FUNCHAR 206
  48. #define E_GENDELIM 207
  49. #define E_SRDELIM 208
  50. #define E_BADKEY 209
  51. #define E_BADQUANTITY 210
  52. #define E_BADNAME 211
  53. #define E_REFNAME 212
  54. #define E_DUPNAME 213
  55. #define E_QUANTITY 214
  56. #define E_QTOOBIG 215
  57. #define E_NMSTRTCNT 219
  58. #define E_NMCHARCNT 220
  59. #define E_NMDUP 221
  60. #define E_NMBAD 222
  61. #define E_NMMINUS 223
  62. #define E_UNKNOWNSET 227
  63.  
  64. #define CANON_NMC '.'        /* Canonical name character. */
  65. #define CANON_NMS 'A'        /* Canonical name start character. */
  66. #define CANON_MIN ':'        /* Canonical minimum data character. */
  67.  
  68. #define SUCCESS 1
  69. #define FAIL 0
  70. #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
  71. #define matches(tok, str) (ustrcmp((tok)+1, (str)) == 0)
  72.  
  73. static UNCH standard[] = "ISO 8879:1986";
  74.  
  75. #define REFERENCE_SYNTAX "ISO 8879:1986//SYNTAX Reference//EN"
  76. #define CORE_SYNTAX "ISO 8879:1986//SYNTAX Core//EN"
  77.  
  78. static UNCH (*newkey)[REFNAMELEN+1] = 0;
  79.  
  80. struct pmap {
  81.      char *name;
  82.      UNIV value;
  83. };
  84.  
  85. /* The reference capacity set. */
  86. #define REFCAPSET \
  87. { 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, \
  88. 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L }
  89.  
  90. long refcapset[NCAPACITY] = REFCAPSET;
  91.  
  92. /* A pmap of known capacity sets. */
  93.  
  94. static struct pmap capset_map[] = {
  95.      { "ISO 8879:1986//CAPACITY Reference//EN", (UNIV)refcapset },
  96.      { 0 },
  97. };
  98.  
  99. /* Table of capacity names.  Must match *CAP in sgmldecl.h. */
  100.  
  101. char *captab[] = {
  102.      "TOTALCAP",
  103.      "ENTCAP",
  104.      "ENTCHCAP",
  105.      "ELEMCAP",
  106.      "GRPCAP",
  107.      "EXGRPCAP",
  108.      "EXNMCAP",
  109.      "ATTCAP",
  110.      "ATTCHCAP",
  111.      "AVGRPCAP",
  112.      "NOTCAP",
  113.      "NOTCHCAP",
  114.      "IDCAP",
  115.      "IDREFCAP",
  116.      "MAPCAP",
  117.      "LKSETCAP",
  118.      "LKNMCAP",
  119. };
  120.  
  121. /* The default SGML declaration. */
  122. #define MAXNUMBER 99999999L
  123.  
  124. /* Reference quantity set */
  125.  
  126. #define REFATTCNT 40
  127. #define REFATTSPLEN 960
  128. #define REFBSEQLEN 960
  129. #define REFDTAGLEN 16
  130. #define REFDTEMPLEN 16
  131. #define REFENTLVL 16
  132. #define REFGRPCNT 32
  133. #define REFGRPGTCNT 96
  134. #define REFGRPLVL 16
  135. #define REFNORMSEP 2
  136. #define REFPILEN 240
  137. #define REFTAGLEN 960
  138. #define REFTAGLVL 24
  139.  
  140. #define ALLOC_MAX 65534
  141.  
  142. #define BIGINT 30000
  143.  
  144. #define MAXATTCNT ((ALLOC_MAX/sizeof(struct ad)) - 2)
  145. #define MAXATTSPLEN BIGINT
  146. #define MAXBSEQLEN BIGINT
  147. #define MAXDTAGLEN 16
  148. #define MAXDTEMPLEN 16
  149. #define MAXENTLVL ((ALLOC_MAX/sizeof(struct source)) - 1)
  150. #define MAXGRPCNT MAXGRPGTCNT
  151. /* Must be between 96 and 253 */
  152. #define MAXGRPGTCNT 253
  153. #define MAXGRPLVL MAXGRPGTCNT
  154. #define MAXLITLEN BIGINT
  155. /* This guarantees that NAMELEN < LITLEN (ie there's always space for a name
  156. in a buffer intended for a literal.) */
  157. #define MAXNAMELEN (REFLITLEN - 1)
  158. #define MAXNORMSEP 2
  159. #define MAXPILEN BIGINT
  160. #define MAXTAGLEN BIGINT
  161. #define MAXTAGLVL ((ALLOC_MAX/sizeof(struct tag)) - 1)
  162.  
  163. /* Table of quantity names.  Must match Q* in sgmldecl.h. */
  164.  
  165. static char *quantity_names[] = {
  166.     "ATTCNT",   
  167.     "ATTSPLEN", 
  168.     "BSEQLEN",  
  169.     "DTAGLEN",  
  170.     "DTEMPLEN", 
  171.     "ENTLVL",   
  172.     "GRPCNT",   
  173.     "GRPGTCNT", 
  174.     "GRPLVL",   
  175.     "LITLEN",   
  176.     "NAMELEN",  
  177.     "NORMSEP",  
  178.     "PILEN",    
  179.     "TAGLEN",   
  180.     "TAGLVL",    
  181. };
  182.  
  183. static int max_quantity[] = {
  184.     MAXATTCNT,
  185.     MAXATTSPLEN,
  186.     MAXBSEQLEN,
  187.     MAXDTAGLEN,
  188.     MAXDTEMPLEN,
  189.     MAXENTLVL,
  190.     MAXGRPCNT,
  191.     MAXGRPGTCNT,
  192.     MAXGRPLVL,
  193.     MAXLITLEN,
  194.     MAXNAMELEN,
  195.     MAXNORMSEP,
  196.     MAXPILEN,
  197.     MAXTAGLEN,
  198.     MAXTAGLVL,
  199. };
  200.  
  201. static char *quantity_changed;
  202.  
  203. /* Non-zero means the APPINFO parameter was not NONE. */
  204. static int appinfosw = 0;
  205.  
  206. struct sgmldecl sd = {
  207.      REFCAPSET,            /* capacity */
  208. #ifdef SUPPORT_SUBDOC
  209.      MAXNUMBER,            /* subdoc */
  210. #else /* not SUPPORT_SUBDOC */
  211.      0,                /* subdoc */
  212. #endif /* not SUPPORT_SUBDOC */
  213.      1,                /* formal */
  214.      1,                /* omittag */
  215.      1,                /* shorttag */
  216.      1,                /* shortref */
  217.      { 1, 0 },            /* general/entity name case translation */
  218.      {                /* reference quantity set */
  219.       REFATTCNT,
  220.       REFATTSPLEN,
  221.       REFBSEQLEN,
  222.       REFDTAGLEN,
  223.       REFDTEMPLEN,
  224.       REFENTLVL,
  225.       REFGRPCNT,
  226.       REFGRPGTCNT,
  227.       REFGRPLVL,
  228.       REFLITLEN,
  229.       REFNAMELEN,
  230.       REFNORMSEP,
  231.       REFPILEN,
  232.       REFTAGLEN,
  233.       REFTAGLVL,
  234.      },
  235. };
  236.  
  237. static int systemcharset[] = {
  238. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  239. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  240. 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  241. 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  242. 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  243. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  244. 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  245. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  246. 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
  247. 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  248. 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
  249. 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
  250. 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
  251. 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
  252. 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
  253. 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
  254. };
  255.  
  256. static struct pmap charset_map[] = {
  257.      { "ESC 2/5 4/0", (UNIV)asciicharset }, /* ISO 646 IRV */
  258.      { "ESC 2/8 4/2", (UNIV)asciicharset }, /* ISO Registration Number 6, ASCII */
  259.      { SYSTEM_CHARSET_DESIGNATING_SEQUENCE, (UNIV)systemcharset },
  260.                 /* system character set */
  261.      { 0 }
  262. };
  263.  
  264. static int synrefcharset[256];    /* the syntax reference character set */
  265.  
  266. #define CHAR_NONSGML 01
  267. #define CHAR_SIGNIFICANT 02
  268. #define CHAR_MAGIC 04
  269. #define CHAR_SHUNNED 010
  270.  
  271. static UNCH char_flags[256];
  272. static int done_nonsgml = 0;
  273. static UNCH *nlextoke = 0;    /* new lextoke */
  274. static UNCH *nlextran = 0;    /* new lextran */
  275.  
  276.  
  277. static UNCH kcharset[] = "CHARSET";
  278. static UNCH kbaseset[] = "BASESET";
  279. static UNCH kdescset[] = "DESCSET";
  280. static UNCH kunused[] = "UNUSED";
  281. static UNCH kcapacity[] = "CAPACITY";
  282. static UNCH kpublic[] = "PUBLIC";
  283. static UNCH ksgmlref[] = "SGMLREF";
  284. static UNCH kscope[] = "SCOPE";
  285. static UNCH kdocument[] = "DOCUMENT";
  286. static UNCH kinstance[] = "INSTANCE";
  287. static UNCH ksyntax[] = "SYNTAX";
  288. static UNCH kswitches[] = "SWITCHES";
  289. static UNCH kfeatures[] = "FEATURES";
  290. static UNCH kminimize[] = "MINIMIZE";
  291. static UNCH kdatatag[] = "DATATAG";
  292. static UNCH komittag[] = "OMITTAG";
  293. static UNCH krank[] = "RANK";
  294. static UNCH kshorttag[] = "SHORTTAG";
  295. static UNCH klink[] = "LINK";
  296. static UNCH ksimple[] = "SIMPLE";
  297. static UNCH kimplicit[] = "IMPLICIT";
  298. static UNCH kexplicit[] = "EXPLICIT";
  299. static UNCH kother[] = "OTHER";
  300. static UNCH kconcur[] = "CONCUR";
  301. static UNCH ksubdoc[] = "SUBDOC";
  302. static UNCH kformal[] = "FORMAL";
  303. static UNCH kyes[] = "YES";
  304. static UNCH kno[] = "NO";
  305. static UNCH kappinfo[] = "APPINFO";
  306. static UNCH knone[] = "NONE";
  307. static UNCH kshunchar[] = "SHUNCHAR";
  308. static UNCH kcontrols[] = "CONTROLS";
  309. static UNCH kfunction[] = "FUNCTION";
  310. static UNCH krs[] = "RS";
  311. static UNCH kre[] = "RE";
  312. static UNCH kspace[] = "SPACE";
  313. static UNCH knaming[] = "NAMING";
  314. static UNCH klcnmstrt[] = "LCNMSTRT";
  315. static UNCH kucnmstrt[] = "UCNMSTRT";
  316. static UNCH klcnmchar[] = "LCNMCHAR";
  317. static UNCH kucnmchar[] = "UCNMCHAR";
  318. static UNCH knamecase[] = "NAMECASE";
  319. static UNCH kdelim[] = "DELIM";
  320. static UNCH kgeneral[] = "GENERAL";
  321. static UNCH kentity[] = "ENTITY";
  322. static UNCH kshortref[] = "SHORTREF";
  323. static UNCH knames[] = "NAMES";
  324. static UNCH kquantity[] = "QUANTITY";
  325.  
  326. #define sderr mderr
  327.  
  328. static UNIV pmaplookup P((struct pmap *, char *));
  329. static UNCH *ltous P((long));
  330. static VOID sdfixstandard P((UNCH *));
  331. static int sdparm P((UNCH *, struct parse *));
  332. static int sdname P((UNCH *, UNCH *));
  333. static int sdckname P((UNCH *, UNCH *));
  334. static int sdversion P((UNCH *));
  335. static int sdcharset P((UNCH *));
  336. static int sdcsdesc P((UNCH *, int *));
  337. static int sdpubcapacity P((UNCH *));
  338. static int sdcapacity P((UNCH *));
  339. static int sdscope P((UNCH *));
  340. static VOID setlexical P((void));
  341. static VOID noemptytag P((void));
  342. static int sdpubsyntax P((UNCH *));
  343. static int sdsyntax P((UNCH *));
  344. static int sdxsyntax P((UNCH *));
  345. static int sdtranscharnum P((UNCH *));
  346. static int sdtranschar P((int));
  347. static int sdshunchar P((UNCH *));
  348. static int sdsynref P((UNCH *));
  349. static int sdfunction P((UNCH *));
  350. static int sdnaming P((UNCH *));
  351. static int sddelim P((UNCH *));
  352. static int sdnames P((UNCH *));
  353. static int sdquantity P((UNCH *));
  354. static int sdfeatures P((UNCH *));
  355. static int sdappinfo P((UNCH *));
  356.  
  357. static VOID bufsalloc P((void));
  358. static VOID bufsrealloc P((void));
  359.  
  360. /* Parse the SGML declaration. Return non-zero if there was some appinfo. */
  361.  
  362. int sgmldecl()
  363. {
  364.      int i;
  365.      int errsw = 0;
  366.      UNCH endbuf[REFNAMELEN+2];    /* buffer for parsing terminating > */
  367.      static int (*section[]) P((UNCH *)) = {
  368.       sdversion,
  369.       sdcharset,
  370.       sdcapacity,
  371.       sdscope,
  372.       sdsyntax,
  373.       sdfeatures,
  374.       sdappinfo,
  375.      };
  376.      /* These are needed if we use mderr. */
  377.      parmno = 0;
  378.      mdname = sgmlkey;
  379.      subdcl = NULL;
  380.      for (i = 0; i < SIZEOF(section); i++)
  381.       if ((*section[i])(tbuf) == FAIL) {
  382.            errsw = 1;
  383.            break;
  384.       }
  385.      if (!errsw)
  386.       setlexical();
  387.      bufsrealloc();
  388.      /* Parse the >.  Don't overwrite the appinfo. */
  389.      if (!errsw)
  390.       sdparm(endbuf, 0);
  391.      /* We must exit if we hit end of document. */
  392.      if (pcbsd.action == EOD_)
  393.       exiterr(161, &pcbsd);
  394.      if (!errsw && pcbsd.action != ESGD)
  395.       sderr(126, (UNCH *)0, (UNCH *)0);
  396.      return appinfosw;
  397. }
  398.  
  399. /* Parse the literal (which should contain the version of the
  400. standard) at the beginning of a SGML declaration. */
  401.  
  402. static int sdversion(tbuf)
  403. UNCH *tbuf;
  404. {
  405.      if (sdparm(tbuf, &pcblitv) != LIT1) {
  406.       sderr(123, (UNCH *)0, (UNCH *)0);
  407.       return FAIL;
  408.      }
  409.      sdfixstandard(tbuf);
  410.      if (ustrcmp(tbuf, standard) != 0)
  411.       sderr(E_BADVERSION, tbuf, standard);
  412.      return SUCCESS;
  413. }
  414.  
  415. /* Parse the CHARSET section. Use one token lookahead. */
  416.  
  417. static int sdcharset(tbuf)
  418. UNCH *tbuf;
  419. {
  420.      int i;
  421.      int status[256];
  422.  
  423.      if (sdname(tbuf, kcharset) == FAIL) return FAIL;
  424.      (void)sdparm(tbuf, 0);
  425.  
  426.      if (sdcsdesc(tbuf, status) == FAIL)
  427.       return FAIL;
  428.  
  429.      for (i = 128; i < 256; i++)
  430.       if (status[i] != UNDESC)
  431.            break;
  432.      if (i >= 256) {
  433.       /* Only a 7-bit character set was described.  Fill it out to 8-bits. */
  434.       for (i = 128; i < 256; i++)
  435.            status[i] = UNUSED;
  436. #if 0
  437.       sderr(E_7BIT, (UNCH *)0, (UNCH *)0);
  438. #endif
  439.      }
  440.      /* Characters that are declared UNUSED in the document character set
  441.     are assigned to non-SGML. */
  442.      for (i = 0; i < 256; i++) {
  443.       if (status[i] == UNDESC) {
  444.            sderr(E_CHARMISSING, ltous((long)i), (UNCH *)0);
  445.            char_flags[i] |= CHAR_NONSGML;
  446.       }
  447.       else if (status[i] == UNUSED)
  448.            char_flags[i] |= CHAR_NONSGML;
  449.      }
  450.      done_nonsgml = 1;
  451.      return SUCCESS;
  452. }
  453.  
  454. /* Parse a character set description.   Uses one character lookahead. */
  455.  
  456. static int sdcsdesc(tbuf, status)
  457. UNCH *tbuf;
  458. int *status;
  459. {
  460.      int i;
  461.      int nsets = 0;
  462.      struct fpi fpi;
  463.  
  464.      for (i = 0; i < 256; i++)
  465.       status[i] = UNDESC;
  466.  
  467.      for (;;) {
  468.       int nchars;
  469.       int *baseset = 0;
  470.  
  471.       if (pcbsd.action != NAS1) {
  472.            if (nsets == 0) {
  473.             sderr(120, (UNCH *)0, (UNCH *)0);
  474.             return FAIL;
  475.            }
  476.            break;
  477.       }
  478.       if (!matches(tbuf, kbaseset)) {
  479.            if (nsets == 0) {
  480.             sderr(118, tbuf+1, kbaseset);
  481.             return FAIL;
  482.            }
  483.            break;
  484.       }
  485.       nsets++;
  486.       MEMZERO((UNIV)&fpi, FPISZ);
  487.       if (sdparm(tbuf, &pcblitv) != LIT1) {
  488.            sderr(123, (UNCH *)0, (UNCH *)0);
  489.            return FAIL;
  490.       }
  491.       fpi.fpipubis = tbuf;
  492.       /* Give a warning if it is not a CHARSET fpi. */
  493.       if (parsefpi(&fpi))
  494.            sderr(E_FORMAL, (UNCH *)0, (UNCH *)0);
  495.       else if (fpi.fpic != FPICHARS)
  496.            sderr(E_BADCLASS, kcharset, (UNCH *)0);
  497.       else {
  498.            fpi.fpipubis[fpi.fpil + fpi.fpill] = '\0';
  499.            baseset = (int *)pmaplookup(charset_map,
  500.                        (char *)fpi.fpipubis + fpi.fpil);
  501.            if (!baseset)
  502.             sderr(E_UNKNOWNSET, fpi.fpipubis + fpi.fpil, (UNCH *)0);
  503.       }
  504.       if (sdname(tbuf, kdescset) == FAIL) return FAIL;
  505.       nchars = 0;
  506.       for (;;) {
  507.            long start, count;
  508.            long basenum;
  509.            if (sdparm(tbuf, 0) != NUM1)
  510.             break;
  511.            start = atol((char *)tbuf);
  512.            if (sdparm(tbuf, 0) != NUM1) {
  513.             sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  514.             return FAIL;
  515.            }
  516.            count = atol((char *)tbuf);
  517.            switch (sdparm(tbuf, &pcblitv)) {
  518.            case NUM1:
  519.             basenum = atol((char *)tbuf);
  520.             break;
  521.            case LIT1:
  522.             basenum = UNKNOWN;
  523.             break;
  524.            case NAS1:
  525.             if (matches(tbuf, kunused)) {
  526.              basenum = UNUSED;
  527.              break;
  528.             }
  529.             /* fall through */
  530.            default:
  531.             sderr(E_CHARDESC, ltous(start), (UNCH *)0);
  532.             return FAIL;
  533.            }
  534.            if (start + count > 256)
  535.             sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
  536.            else {
  537.             int i;
  538.             int lim = (int)start + count;
  539.             for (i = (int)start; i < lim; i++) {
  540.              if (status[i] != UNDESC)
  541.                   sderr(E_CHARDUP, ltous((long)i), (UNCH *)0);
  542.              else if (basenum == UNUSED || basenum == UNKNOWN)
  543.                   status[i] = (int)basenum;
  544.              else if (baseset == 0)
  545.                   status[i] = UNKNOWN_SET;
  546.              else {
  547.                   int n = basenum + (i - start);
  548.                   if (n < 0 || n > 255)
  549.                    sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
  550.                   else if (baseset[n] == UNUSED)
  551.                    sderr(E_BADBASECHAR, ltous((long)n), (UNCH *)0);
  552.                   else
  553.                    status[i] = baseset[n];
  554.              }
  555.             }
  556.            }
  557.            nchars++;
  558.       }
  559.       if (nchars == 0) {
  560.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  561.            return FAIL;
  562.       }
  563.      }
  564.      return SUCCESS;
  565. }
  566.  
  567. /* Parse the CAPACITY section.  Uses one token lookahead. */
  568.  
  569. static int sdcapacity(tbuf)
  570. UNCH *tbuf;
  571. {
  572.      int ncap;
  573.  
  574.      if (sdckname(tbuf, kcapacity) == FAIL)
  575.       return FAIL;
  576.      if (sdparm(tbuf, 0) != NAS1) {
  577.       sderr(120, (UNCH *)0, (UNCH *)0);
  578.       return FAIL;
  579.      }
  580.      if (matches(tbuf, kpublic))
  581.       return sdpubcapacity(tbuf);
  582.      if (!matches(tbuf, ksgmlref)) {
  583.       sderr(E_CAPACITY, tbuf+1, (UNCH *)0);
  584.       return FAIL;
  585.      }
  586.      memcpy((UNIV)sd.capacity, (UNIV)refcapset, sizeof(sd.capacity));
  587.      ncap = 0;
  588.      for (;;) {
  589.       int capno = -1;
  590.       int i;
  591.  
  592.       if (sdparm(tbuf, 0) != NAS1)
  593.            break;
  594.       for (i = 0; i < SIZEOF(captab); i++)
  595.            if (matches(tbuf, captab[i])) {
  596.             capno = i;
  597.             break;
  598.            }
  599.       if (capno < 0)
  600.            break;
  601.       if (sdparm(tbuf, 0) != NUM1) {
  602.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  603.            return FAIL;
  604.       }
  605.       sd.capacity[capno] = atol((char *)tbuf);
  606.       ncap++;
  607.      }
  608.      if (ncap == 0) {
  609.       sderr(E_CAPMISSING, (UNCH *)0, (UNCH *)0);
  610.       return FAIL;
  611.      }
  612.  
  613.      return SUCCESS;
  614. }
  615.  
  616. /* Parse a CAPACITY section that started with PUBLIC.  Must do one
  617. token lookahead, since sdcapacity() also does. */
  618.  
  619. static int sdpubcapacity(tbuf)
  620. UNCH *tbuf;
  621. {
  622.      UNIV ptr;
  623.      if (sdparm(tbuf, &pcblitv) != LIT1) {
  624.       sderr(123, (UNCH *)0, (UNCH *)0);
  625.       return FAIL;
  626.      }
  627.      sdfixstandard(tbuf);
  628.      ptr = pmaplookup(capset_map, (char *)tbuf);
  629.      if (!ptr)
  630.       sderr(E_CAPSET, tbuf, (UNCH *)0);
  631.      else
  632.       memcpy((UNIV)sd.capacity, (UNIV)ptr, sizeof(sd.capacity));
  633.      (void)sdparm(tbuf, 0);
  634.      return SUCCESS;
  635. }
  636.  
  637. /* Parse the SCOPE section. Uses no lookahead. */
  638.  
  639. static int sdscope(tbuf)
  640. UNCH *tbuf;
  641. {
  642.      if (sdckname(tbuf, kscope) == FAIL)
  643.       return FAIL;
  644.      if (sdparm(tbuf, 0) != NAS1) {
  645.       sderr(120, (UNCH *)0, (UNCH *)0);
  646.       return FAIL;
  647.      }
  648.      if (matches(tbuf, kdocument))
  649.       ;
  650.      else if (matches(tbuf, kinstance))
  651.       sderr(E_INSTANCE, (UNCH *)0, (UNCH *)0);
  652.      else {
  653.       sderr(E_SCOPE, tbuf+1, (UNCH *)0);
  654.       return FAIL;
  655.      }
  656.      return SUCCESS;
  657. }
  658.  
  659. /* Parse the SYNTAX section.  Uses one token lookahead. */
  660.  
  661. static int sdsyntax(tbuf)
  662. UNCH *tbuf;
  663. {
  664.      if (sdname(tbuf, ksyntax) == FAIL) return FAIL;
  665.      if (sdparm(tbuf, 0) != NAS1) {
  666.       sderr(120, (UNCH *)0, (UNCH *)0);
  667.       return FAIL;
  668.      }
  669.      if (matches(tbuf, kpublic))
  670.       return sdpubsyntax(tbuf);
  671.      return sdxsyntax(tbuf);
  672. }
  673.  
  674. /* Parse the SYNTAX section which starts with PUBLIC.  Uses one token
  675. lookahead. */
  676.  
  677. static int sdpubsyntax(tbuf)
  678. UNCH *tbuf;
  679. {
  680.      int nswitches;
  681.      if (sdparm(tbuf, &pcblitv) != LIT1)
  682.       return FAIL;
  683.      sdfixstandard(tbuf);
  684.      if (ustrcmp(tbuf, CORE_SYNTAX) == 0)
  685.       sd.shortref = 0;
  686.      else if (ustrcmp(tbuf, REFERENCE_SYNTAX) == 0)
  687.       sd.shortref = 1;
  688.      else
  689.       sderr(E_SYNTAX, tbuf, (UNCH *)0);
  690.      if (sdparm(tbuf, 0) != NAS1)
  691.       return SUCCESS;
  692.      if (!matches(tbuf, kswitches))
  693.       return SUCCESS;
  694.      nswitches = 0;
  695.      for (;;) {
  696.       int errsw = 0;
  697.  
  698.       if (sdparm(tbuf, 0) != NUM1)
  699.            break;
  700.       if (atol((char *)tbuf) > 255) {
  701.            sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  702.            errsw = 1;
  703.       }
  704.       if (sdparm(tbuf, 0) != NUM1) {
  705.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  706.            return FAIL;
  707.       }
  708.       if (!errsw) {
  709.            if (atol((char *)tbuf) > 255)
  710.             sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  711.       }
  712.       nswitches++;
  713.      }
  714.      if (nswitches == 0) {
  715.       sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  716.       return FAIL;
  717.      }
  718.      sderr(E_SWITCHES, (UNCH *)0, (UNCH *)0);
  719.      return SUCCESS;
  720. }
  721.  
  722. /* Parse an explicit concrete syntax. Uses one token lookahead. */
  723.  
  724. static
  725. int sdxsyntax(tbuf)
  726. UNCH *tbuf;
  727. {
  728.      static int (*section[]) P((UNCH *)) = {
  729.       sdshunchar,
  730.       sdsynref,
  731.       sdfunction,
  732.       sdnaming,
  733.       sddelim,
  734.       sdnames,
  735.       sdquantity,
  736.      };
  737.      int i;
  738.  
  739.      for (i = 0; i < SIZEOF(section); i++)
  740.       if ((*section[i])(tbuf) == FAIL)
  741.            return FAIL;
  742.      return SUCCESS;
  743. }
  744.  
  745. /* Parse the SHUNCHAR section. Uses one token lookahead. */
  746.  
  747. static
  748. int sdshunchar(tbuf)
  749. UNCH *tbuf;
  750. {
  751.      int i;
  752.      for (i = 0; i < 256; i++)
  753.       char_flags[i] &= ~CHAR_SHUNNED;
  754.  
  755.      if (sdckname(tbuf, kshunchar) == FAIL)
  756.       return FAIL;
  757.  
  758.      if (sdparm(tbuf, 0) == NAS1) {
  759.       if (matches(tbuf, knone)) {
  760.            (void)sdparm(tbuf, 0);
  761.            return SUCCESS;
  762.       }
  763.       if (matches(tbuf, kcontrols)) {
  764.            for (i = 0; i < 256; i++)
  765.             if (ISASCII(i) && iscntrl(i))
  766.              char_flags[i] |= CHAR_SHUNNED;
  767.            if (sdparm(tbuf, 0) != NUM1)
  768.             return SUCCESS;
  769.       }
  770.      }
  771.      if (pcbsd.action != NUM1) {
  772.       sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  773.       return FAIL;
  774.      }
  775.      do {
  776.       long n = atol((char *)tbuf);
  777.       if (n > 255)
  778.            sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  779.       else
  780.            char_flags[(int)n] |= CHAR_SHUNNED;
  781.      } while (sdparm(tbuf, 0) == NUM1);
  782.      return SUCCESS;
  783. }
  784.  
  785. /* Parse the syntax reference character set. Uses one token lookahead. */
  786.  
  787. static
  788. int sdsynref(tbuf)
  789. UNCH *tbuf;
  790. {
  791.      return sdcsdesc(tbuf, synrefcharset);
  792. }
  793.  
  794. /* Translate a character number from the syntax reference character set
  795. to the system character set. If it can't be done, give an error message
  796. and return -1. */
  797.  
  798. static
  799. int sdtranscharnum(tbuf)
  800. UNCH *tbuf;
  801. {
  802.      long n = atol((char *)tbuf);
  803.      if (n > 255) {
  804.       sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  805.       return -1;
  806.      }
  807.      return sdtranschar((int)n);
  808. }
  809.  
  810.  
  811. static
  812. int sdtranschar(n)
  813. int n;
  814. {
  815.      int ch = synrefcharset[n];
  816.      if (ch >= 0)
  817.       return ch;
  818.      switch (ch) {
  819.      case UNUSED:
  820.       sderr(E_SYNREFUNUSED, ltous((long)n), (UNCH *)0);
  821.       break;
  822.      case UNDESC:
  823.       sderr(E_SYNREFUNDESC, ltous((long)n), (UNCH *)0);
  824.       break;
  825.      case UNKNOWN:
  826.       sderr(E_SYNREFUNKNOWN, ltous((long)n), (UNCH *)0);
  827.       break;
  828.      case UNKNOWN_SET:
  829.       sderr(E_SYNREFUNKNOWNSET, ltous((long)n), (UNCH *)0);
  830.       break;
  831.      default:
  832.       abort();
  833.      }
  834.      return -1;
  835. }
  836.  
  837.  
  838. /* Parse the function section. Uses two tokens lookahead. "NAMING"
  839. could be a function name. */
  840.  
  841. static
  842. int sdfunction(tbuf)
  843. UNCH *tbuf;
  844. {
  845.      static UNCH *fun[] = { kre, krs, kspace };
  846.      static int funval[] = { RECHAR, RSCHAR, ' ' };
  847.      int i;
  848.      int had_tab = 0;
  849.      int changed = 0;        /* attempted to change reference syntax */
  850.  
  851.      if (sdckname(tbuf, kfunction) == FAIL)
  852.       return FAIL;
  853.      for (i = 0; i < SIZEOF(fun); i++) {
  854.       int ch;
  855.       if (sdname(tbuf, fun[i]) == FAIL)
  856.            return FAIL;
  857.       if (sdparm(tbuf, 0) != NUM1) {
  858.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  859.            return FAIL;
  860.       }
  861.       ch = sdtranscharnum(tbuf);
  862.       if (ch >= 0 && ch != funval[i])
  863.            changed = 1;
  864.      }
  865.      for (;;) {
  866.       int tabsw = 0;
  867.       int namingsw = 0;
  868.       if (sdparm(tbuf, 0) != NAS1) {
  869.            sderr(120, (UNCH *)0, (UNCH *)0);
  870.            return FAIL;
  871.       }
  872.       if (matches(tbuf, (UNCH *)"TAB")) {
  873.            tabsw = 1;
  874.            if (had_tab)
  875.             sderr(E_FUNDUP, (UNCH *)0, (UNCH *)0);
  876.       }
  877.       else {
  878.            for (i = 0; i < SIZEOF(fun); i++)
  879.             if (matches(tbuf, fun[i]))
  880.              sderr(E_BADFUN, fun[i], (UNCH *)0);
  881.            if (matches(tbuf, knaming))
  882.             namingsw = 1;
  883.            else
  884.             changed = 1;
  885.       }
  886.       if (sdparm(tbuf, 0) != NAS1) {
  887.            sderr(120, (UNCH *)0, (UNCH *)0);
  888.            return FAIL;
  889.       }
  890.       if (namingsw) {
  891.            if (matches(tbuf, klcnmstrt))
  892.             break;
  893.            changed = 1;
  894.       }
  895.       if (sdparm(tbuf, 0) != NUM1) {
  896.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  897.            return FAIL;
  898.       }
  899.       if (tabsw && !had_tab) {
  900.            int ch = sdtranscharnum(tbuf);
  901.            if (ch >= 0 && ch != TABCHAR)
  902.             changed = 1;
  903.            had_tab = 1;
  904.       }
  905.  
  906.      }
  907.      if (!had_tab)
  908.       changed = 1;
  909.      if (changed)
  910.       sderr(E_FUNCHAR, (UNCH *)0, (UNCH *)0);
  911.      return SUCCESS;
  912. }
  913.  
  914. /* Parse the NAMING section.  Uses no lookahead. */
  915.  
  916. static
  917. int sdnaming(tbuf)
  918. UNCH *tbuf;
  919. {
  920.      int i;
  921.      int bad = 0;
  922.      static UNCH *classes[] = { klcnmstrt, kucnmstrt, klcnmchar, kucnmchar };
  923.      static UNCH *types[] = { kgeneral, kentity };
  924.  
  925. #define NCLASSES SIZEOF(classes)
  926.  
  927.      int bufsize = 4;        /* allocated size of buf */
  928.      UNCH *buf = (UNCH *)rmalloc(bufsize); /* holds characters
  929.                           in naming classes */
  930.      int bufi = 0;        /* next index into buf */
  931.      int start[NCLASSES];    /* index of first character for each class */
  932.      int count[NCLASSES];    /* number of characters for each class */
  933.  
  934.      for (i = 0; i < NCLASSES; i++) {
  935.       UNCH *s;
  936.  
  937.       if (sdckname(tbuf, classes[i]) == FAIL) {
  938.            frem((UNIV)buf);
  939.            return FAIL;
  940.       }
  941.       if (sdparm(tbuf, &pcblitp) != LIT1) {
  942.            sderr(123, (UNCH *)0, (UNCH *)0);
  943.            frem((UNIV)buf);
  944.            return FAIL;
  945.       }
  946.       start[i] = bufi;
  947.       
  948.       for (s = tbuf; *s; s++) {
  949.            int c = *s;
  950.            if (c == DELNONCH) {
  951.             c = UNSHIFTNON(*s);
  952.             s++;
  953.            }
  954.            c = sdtranschar(c);
  955.            if (c < 0)
  956.             bad = 1;
  957.            else if ((char_flags[c] & (CHAR_SIGNIFICANT | CHAR_MAGIC))
  958.             && c != '.' && c != '-') {
  959.             int class = lextoke[c];
  960.             if (class == SEP || class == SP || class == NMC
  961.             || class == NMS || class == NU)
  962.              sderr(E_NMBAD, ltous((long)c), (UNCH *)0);
  963.             else
  964.              sderr(E_NMUNSUP, ltous((long)c), (UNCH *)0);
  965.             bad = 1;
  966.            }
  967.            if (bufi >= bufsize)
  968.             buf = (UNCH *)rrealloc((UNIV)buf, bufsize *= 2);
  969.            buf[bufi++] = c;
  970.       }
  971.  
  972.       count[i] = bufi - start[i];
  973.       (void)sdparm(tbuf, 0);
  974.      }
  975.      if (!bad && count[0] != count[1]) {
  976.       sderr(E_NMSTRTCNT, (UNCH *)0, (UNCH *)0);
  977.       bad = 1;
  978.      }
  979.      if (!bad && count[2] != count[3]) {
  980.       sderr(E_NMCHARCNT, (UNCH *)0, (UNCH *)0);
  981.       bad = 1;
  982.      }
  983.      if (!bad) {
  984.       nlextoke = (UNCH *)rmalloc(256);
  985.       memcpy((UNIV)nlextoke, lextoke, 256);
  986.       nlextoke['.'] = nlextoke['-'] = INV;
  987.  
  988.       nlextran = (UNCH *)rmalloc(256);
  989.       memcpy((UNIV)nlextran, lextran, 256);
  990.  
  991.       for (i = 0; i < count[0]; i++) {
  992.            UNCH lc = buf[start[0] + i];
  993.            UNCH uc = buf[start[1] + i];
  994.            nlextoke[lc] = NMS;
  995.            nlextoke[uc] = NMS;
  996.            nlextran[lc] = uc;
  997.       }
  998.                
  999.       for (i = 0; i < count[2]; i++) {
  1000.            UNCH lc = buf[start[2] + i];
  1001.            UNCH uc = buf[start[3] + i];
  1002.            if (nlextoke[lc] == NMS) {
  1003.             sderr(E_NMDUP, ltous((long)lc), (UNCH *)0);
  1004.             bad = 1;
  1005.            }
  1006.            else if (nlextoke[uc] == NMS) {
  1007.             sderr(E_NMDUP, ltous((long)uc), (UNCH *)0);
  1008.             bad = 1;
  1009.            }
  1010.            else {
  1011.             nlextoke[lc] = NMC;
  1012.             nlextoke[uc] = NMC;
  1013.             nlextran[lc] = uc;
  1014.            }
  1015.       }
  1016.       if (nlextoke['-'] != NMC) {
  1017.            sderr(E_NMMINUS, (UNCH *)0, (UNCH *)0);
  1018.            bad = 1;
  1019.       }
  1020.       if (bad) {
  1021.            if (nlextoke) {
  1022.             frem((UNIV)nlextoke);
  1023.             nlextoke = 0;
  1024.            }
  1025.            if (nlextran) {
  1026.             frem((UNIV)nlextran);
  1027.             nlextran = 0;
  1028.            }
  1029.       }
  1030.      }
  1031.  
  1032.      frem((UNIV)buf);
  1033.  
  1034.      if (sdckname(tbuf, knamecase) == FAIL)
  1035.       return FAIL;
  1036.      for (i = 0; i < SIZEOF(types); ++i) {
  1037.       if (sdname(tbuf, types[i]) == FAIL)
  1038.            return FAIL;
  1039.       if (sdparm(tbuf, 0) != NAS1) {
  1040.            sderr(120, (UNCH *)0, (UNCH *)0);
  1041.            return FAIL;
  1042.       }
  1043.       if (matches(tbuf, kyes))
  1044.            sd.namecase[i] = 1;
  1045.       else if (matches(tbuf, kno))
  1046.            sd.namecase[i] = 0;
  1047.       else {
  1048.            sderr(E_YESNO, tbuf+1, (UNCH *)0);
  1049.            return FAIL;
  1050.       }
  1051.      }
  1052.      return SUCCESS;
  1053. }
  1054.  
  1055. /* Parse the DELIM section. Uses one token lookahead. */
  1056.  
  1057. static
  1058. int sddelim(tbuf)
  1059. UNCH *tbuf;
  1060. {
  1061.      int changed = 0;
  1062.      if (sdname(tbuf, kdelim) == FAIL
  1063.      || sdname(tbuf, kgeneral) == FAIL
  1064.      || sdname(tbuf, ksgmlref) == FAIL)
  1065.       return FAIL;
  1066.      for (;;) {
  1067.       if (sdparm(tbuf, 0) != NAS1) {
  1068.            sderr(120, (UNCH *)0, (UNCH *)0);
  1069.            return FAIL;
  1070.       }
  1071.       if (matches(tbuf, kshortref))
  1072.            break;
  1073.       if (sdparm(tbuf, &pcblitp) != LIT1) {
  1074.            sderr(123, (UNCH *)0, (UNCH *)0);
  1075.            return FAIL;
  1076.       }
  1077.       changed = 1;
  1078.      }
  1079.      if (changed) {
  1080.       sderr(E_GENDELIM, (UNCH *)0,(UNCH *)0);
  1081.       changed = 0;
  1082.      }
  1083.      if (sdparm(tbuf, 0) != NAS1) {
  1084.       sderr(120, (UNCH *)0, (UNCH *)0);
  1085.       return FAIL;
  1086.      }
  1087.      if (matches(tbuf, ksgmlref))
  1088.       sd.shortref = 1;
  1089.      else if (matches(tbuf, knone))
  1090.       sd.shortref = 0;
  1091.      else {
  1092.       sderr(118, tbuf+1, ksgmlref);    /* probably they forgot SGMLREF */
  1093.       return FAIL;
  1094.      }
  1095.      while (sdparm(tbuf, &pcblitp) == LIT1)
  1096.       changed = 1;
  1097.      if (changed)
  1098.       sderr(E_SRDELIM, (UNCH *)0, (UNCH *)0);
  1099.      return SUCCESS;
  1100. }
  1101.  
  1102. /* Parse the NAMES section. Uses one token lookahead. */
  1103.  
  1104. static
  1105. int sdnames(tbuf)
  1106. UNCH *tbuf;
  1107. {
  1108.      int i;
  1109.      if (sdckname(tbuf, knames) == FAIL)
  1110.       return FAIL;
  1111.      if (sdname(tbuf, ksgmlref) == FAIL)
  1112.       return FAIL;
  1113.  
  1114.      while (sdparm(tbuf, 0) == NAS1) {
  1115.       int j;
  1116.       if (matches(tbuf, kquantity))
  1117.            break;
  1118.       for (i = 0; i < NKEYS; i++)
  1119.            if (matches(tbuf, key[i]))
  1120.             break;
  1121.       if (i >= NKEYS) {
  1122.            sderr(E_BADKEY, tbuf+1, (UNCH *)0);
  1123.            return FAIL;
  1124.       }
  1125.       if (sdparm(tbuf, &pcblitp) != NAS1) {
  1126.            sderr(120, (UNCH *)0, (UNCH *)0);
  1127.            return FAIL;
  1128.       }
  1129.       if (!newkey) {
  1130.            newkey = (UNCH (*)[REFNAMELEN+1])rmalloc((REFNAMELEN+1)*NKEYS);
  1131.            MEMZERO((UNIV)newkey, (REFNAMELEN+1)*NKEYS);
  1132.       }
  1133.       for (j = 0; j < NKEYS; j++) {
  1134.            if (matches(tbuf, key[j])) {
  1135.             sderr(E_REFNAME, tbuf + 1, (UNCH *)0);
  1136.             break;
  1137.            }
  1138.            if (matches(tbuf, newkey[j])) {
  1139.             sderr(E_DUPNAME, tbuf + 1, (UNCH *)0);
  1140.             break;
  1141.            }
  1142.       }
  1143.       if (j >= NKEYS)
  1144.            ustrcpy(newkey[i], tbuf + 1);
  1145.      }
  1146.      /* Now install the new keys. */
  1147.      if (newkey) {
  1148.       for (i = 0; i < NKEYS; i++)
  1149.            if (newkey[i][0] != '\0') {
  1150.             UNCH temp[REFNAMELEN + 1];
  1151.             
  1152.             ustrcpy(temp, key[i]);
  1153.             ustrcpy(key[i], newkey[i]);
  1154.             ustrcpy(newkey[i], temp);
  1155.            }
  1156.      }
  1157.      return SUCCESS;
  1158. }
  1159.  
  1160. /* Parse the QUANTITY section. Uses one token lookahead. */
  1161.  
  1162. static int sdquantity(tbuf)
  1163. UNCH *tbuf;
  1164. {
  1165.      int quantity[NQUANTITY];
  1166.      int i;
  1167.  
  1168.      for (i = 0; i < NQUANTITY; i++)
  1169.       quantity[i] = -1;
  1170.      if (sdckname(tbuf, kquantity) == FAIL)
  1171.       return FAIL;
  1172.      if (sdname(tbuf, ksgmlref) == FAIL)
  1173.       return FAIL;
  1174.      while (sdparm(tbuf, 0) == NAS1 && !matches(tbuf, kfeatures)) {
  1175.       long n;
  1176.       for (i = 0; i < SIZEOF(quantity_names); i++)
  1177.            if (matches(tbuf, quantity_names[i]))
  1178.             break;
  1179.       if (i >= SIZEOF(quantity_names)) {
  1180.            sderr(E_BADQUANTITY, tbuf + 1, (UNCH *)0);
  1181.            return FAIL;
  1182.       }
  1183.       if (sdparm(tbuf, 0) != NUM1) {
  1184.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  1185.            return FAIL;
  1186.       }
  1187.       n = atol((char *)tbuf);
  1188.       if (n < sd.quantity[i])
  1189.            sderr(E_QUANTITY, (UNCH *)quantity_names[i],
  1190.              ltous((long)sd.quantity[i]));
  1191.       else if (n > max_quantity[i]) {
  1192.            sderr(E_QTOOBIG, (UNCH *)quantity_names[i],
  1193.              ltous((long)max_quantity[i]));
  1194.            quantity[i] = max_quantity[i];
  1195.       }
  1196.       else
  1197.            quantity[i] = (int)n;
  1198.      }
  1199.      for (i = 0; i < NQUANTITY; i++)
  1200.       if (quantity[i] > 0) {
  1201.            sd.quantity[i] = quantity[i];
  1202.            if (!quantity_changed)
  1203.             quantity_changed = (char *)rmalloc(NQUANTITY);
  1204.            quantity_changed[i] = 1;
  1205.       }
  1206.      return SUCCESS;
  1207. }
  1208.  
  1209. /* Parse the FEATURES section.  Uses no lookahead. */
  1210.  
  1211. static int sdfeatures(tbuf)
  1212. UNCH *tbuf;
  1213. {
  1214.      static struct  {
  1215.       UNCH *name;
  1216.       UNCH argtype;  /* 0 = no argument, 1 = boolean, 2 = numeric */
  1217.       UNIV valp;     /* UNCH * if boolean, long * if numeric. */
  1218.      } features[] = {
  1219.       { kminimize, 0, 0 },
  1220.       { kdatatag, 1, 0 },
  1221.       { komittag, 1, (UNIV)&sd.omittag },
  1222.       { krank, 1, 0 },
  1223.       { kshorttag, 1, (UNIV)&sd.shorttag },
  1224.       { klink, 0, 0 },
  1225.       { ksimple, 2, 0 },
  1226.       { kimplicit, 1, 0 },
  1227.       { kexplicit, 2, 0 },
  1228.       { kother, 0, 0 },
  1229.       { kconcur, 2, 0 },
  1230.       { ksubdoc, 2, (UNIV)&sd.subdoc },
  1231.       { kformal, 1, (UNIV)&sd.formal },
  1232.      };
  1233.  
  1234.      int i;
  1235.  
  1236.      if (sdckname(tbuf, kfeatures) == FAIL)
  1237.       return FAIL;
  1238.      for (i = 0; i < SIZEOF(features); i++) {
  1239.       if (sdname(tbuf, features[i].name) == FAIL) return FAIL;
  1240.       if (features[i].argtype > 0) {
  1241.            long n;
  1242.            if (sdparm(tbuf, 0) != NAS1) {
  1243.             sderr(120, (UNCH *)0, (UNCH *)0);
  1244.             return FAIL;
  1245.            }
  1246.            if (matches(tbuf, kyes)) {
  1247.             if (features[i].argtype > 1) {
  1248.              if (sdparm(tbuf, 0) != NUM1) {
  1249.                   sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  1250.                   return FAIL;
  1251.              }
  1252.              n = atol((char *)tbuf);
  1253.              if (n == 0)
  1254.                   sderr(E_ZEROFEATURE, features[i].name, (UNCH *)0);
  1255.             }
  1256.             else
  1257.              n = 1;
  1258.            }
  1259.            else if (matches(tbuf, kno))
  1260.             n = 0;
  1261.            else {
  1262.             sderr(E_YESNO, tbuf+1, (UNCH *)0);
  1263.             return FAIL;
  1264.            }
  1265.            if (features[i].valp == 0) {
  1266.             if (n > 0)
  1267.              sderr(E_NOTSUPPORTED, features[i].name,
  1268.                   (UNCH *)0);
  1269.            }
  1270.            else if (features[i].argtype > 1)
  1271.             *(long *)features[i].valp = n;
  1272.            else
  1273.             *(UNCH *)features[i].valp = (UNCH)n;
  1274.       }
  1275.      }
  1276.      if (!sd.shorttag)
  1277.       noemptytag();
  1278.      return SUCCESS;
  1279. }
  1280.  
  1281. /* Parse the APPINFO section.  Uses no lookahead. */
  1282.  
  1283. static int sdappinfo(tbuf)
  1284. UNCH *tbuf;
  1285. {
  1286.      if (sdname(tbuf, kappinfo) == FAIL) return FAIL;
  1287.      switch (sdparm(tbuf, &pcblitv)) {
  1288.      case LIT1:
  1289.       appinfosw = 1;
  1290.       break;
  1291.      case NAS1:
  1292.       if (matches(tbuf, knone))
  1293.            break;
  1294.       sderr(118, tbuf+1, knone);
  1295.       return FAIL;
  1296.      default:
  1297.       sderr(E_XNMLIT, knone, (UNCH *)0);
  1298.       return FAIL;
  1299.      }
  1300.      return SUCCESS;
  1301. }
  1302.  
  1303. /* Change a prefix of ISO 8879-1986 to ISO 8879:1986.  Amendment 1 to
  1304. the standard requires the latter. */
  1305.  
  1306. static VOID sdfixstandard(tbuf)
  1307. UNCH *tbuf;
  1308. {
  1309.      if (strncmp((char *)tbuf, "ISO 8879-1986", 13) == 0) {
  1310.       sderr(E_STANDARD, (UNCH *)0, (UNCH *)0);
  1311.       tbuf[8] = ':';
  1312.      }
  1313. }
  1314.  
  1315. static int sdname(tbuf, key)
  1316. UNCH *tbuf;
  1317. UNCH *key;
  1318. {
  1319.      if (sdparm(tbuf, 0) != NAS1) {
  1320.       sderr(120, (UNCH *)0, (UNCH *)0);
  1321.       return FAIL;
  1322.      }
  1323.      if (!matches(tbuf, key)) {
  1324.       sderr(118, tbuf+1, key);
  1325.       return FAIL;
  1326.      }
  1327.      return SUCCESS;
  1328. }
  1329.  
  1330. static int sdckname(tbuf, key)
  1331. UNCH *tbuf;
  1332. UNCH *key;
  1333. {
  1334.      if (pcbsd.action != NAS1) {
  1335.       sderr(120, (UNCH *)0, (UNCH *)0);
  1336.       return FAIL;
  1337.      }
  1338.      if (!matches(tbuf, key)) {
  1339.       sderr(118, tbuf+1, key);
  1340.       return FAIL;
  1341.      }
  1342.      return SUCCESS;
  1343. }
  1344.  
  1345. /* Parse a SGML declaration parameter.  If lpcb is NULL, pt must be
  1346. REFNAMELEN+2 characters long, otherwise at least LITLEN+2 characters
  1347. long. LPCB should be NULL if a literal is not allowed. */
  1348.  
  1349. static int sdparm(pt, lpcb)
  1350. UNCH *pt;            /* Token buffer. */
  1351. struct parse *lpcb;        /* PCB for literal parse. */
  1352. {
  1353.      for (;;) {
  1354.       parse(&pcbsd);
  1355.       if (pcbsd.action != ISIG)
  1356.            break;
  1357.       sderr(E_SIGNIFICANT, (UNCH *)0, (UNCH *)0);
  1358.      }
  1359.      ++parmno;
  1360.      switch (pcbsd.action) {
  1361.      case LIT1:
  1362.       if (!lpcb) {
  1363.            sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
  1364.            REPEATCC;
  1365.            return pcbsd.action = INV_;
  1366.       }
  1367.       parselit(pt, lpcb, REFLITLEN, lex.d.lit);
  1368.       return pcbsd.action;
  1369.      case LIT2:
  1370.       if (!lpcb) {
  1371.            sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
  1372.            REPEATCC;
  1373.            return pcbsd.action = INV_;
  1374.       }
  1375.       parselit(pt, lpcb, REFLITLEN, lex.d.lita);
  1376.       return pcbsd.action = LIT1;
  1377.      case NAS1:
  1378.       parsenm(pt, 1);
  1379.       return pcbsd.action;
  1380.      case NUM1:
  1381.       parsetkn(pt, NU, REFNAMELEN);
  1382.       return pcbsd.action;
  1383.      }
  1384.      return pcbsd.action;
  1385. }
  1386.  
  1387. VOID sdinit()
  1388. {
  1389.      int i;
  1390.      /* Shunned character numbers in the reference concrete syntax. */
  1391.      static UNCH refshun[] = { 
  1392.       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  1393.       19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 255
  1394.       };
  1395.      UNCH **p;
  1396.      /* A character is magic if it is a non-SGML character used for
  1397.      some internal purpose in the parser. */
  1398.      char_flags[EOS] |= CHAR_MAGIC;
  1399.      char_flags[EOBCHAR] |= CHAR_MAGIC;
  1400.      char_flags[EOFCHAR] |= CHAR_MAGIC;
  1401.      char_flags[GENRECHAR] |= CHAR_MAGIC;
  1402.      char_flags[DELNONCH] |= CHAR_MAGIC;
  1403.      char_flags[DELCDATA] |= CHAR_MAGIC;
  1404.      char_flags[DELSDATA] |= CHAR_MAGIC;
  1405.  
  1406.      /* Figure out the significant SGML characters. */
  1407.      for (p = lextabs; *p; p++) {
  1408.       UNCH datclass = (*p)[CANON_DATACHAR];
  1409.       UNCH nonclass = (*p)[CANON_NONSGML];
  1410.       for (i = 0; i < 256; i++)
  1411.            if (!(char_flags[i] & CHAR_MAGIC)
  1412.            && (*p)[i] != datclass && (*p)[i] != nonclass)
  1413.             char_flags[i] |= CHAR_SIGNIFICANT;
  1414.      }
  1415.      for (i = 0; i < SIZEOF(refshun); i++)
  1416.       char_flags[refshun[i]] |= CHAR_SHUNNED;
  1417.      for (i = 0; i < 256; i++)
  1418.       if (ISASCII(i) && iscntrl(i))
  1419.            char_flags[i] |= CHAR_SHUNNED;
  1420.      bufsalloc();
  1421. }
  1422.  
  1423.  
  1424. static
  1425. VOID bufsalloc()
  1426. {
  1427.      scbs = (struct source *)rmalloc((REFENTLVL+1)*sizeof(struct source));
  1428.      tbuf = (UNCH *)rmalloc(REFATTSPLEN+REFLITLEN+1);
  1429.      /* entbuf is used for parsing numeric character references */
  1430.      entbuf = (UNCH *)rmalloc(REFNAMELEN + 2);
  1431. }
  1432.  
  1433. static
  1434. VOID bufsrealloc()
  1435. {
  1436.      UNS size;
  1437.      
  1438.      if (ENTLVL != REFENTLVL)
  1439.       scbs = (struct source *)rrealloc((UNIV)scbs,
  1440.                        (ENTLVL+1)*sizeof(struct source));
  1441.      /* Calculate the size for tbuf. */
  1442.      size = LITLEN + ATTSPLEN;
  1443.      if (PILEN > size)
  1444.       size = PILEN;
  1445.      if (BSEQLEN > size)
  1446.       size = BSEQLEN;
  1447.      if (size != REFATTSPLEN + REFLITLEN)
  1448.       tbuf = (UNCH *)rrealloc((UNIV)tbuf, size + 1);
  1449.      if (NAMELEN != REFNAMELEN)
  1450.       entbuf = (UNCH *)rrealloc((UNIV)entbuf, NAMELEN + 2);
  1451. }
  1452.  
  1453.  
  1454. /* Check that the non-SGML characters are compatible with the concrete
  1455. syntax and munge the lexical tables accordingly.  If IMPLIED is
  1456. non-zero, then the SGML declaration was implied; in this case, don't
  1457. give error messages about shunned characters not being declared
  1458. non-SGML.  Also make any changes that are required by the NAMING section.
  1459. */
  1460.  
  1461. static VOID setlexical()
  1462. {
  1463.      int i;
  1464.      UNCH **p;
  1465.      
  1466.      if (nlextoke) {
  1467.       /* Handle characters that were made significant by the
  1468.          NAMING section. */
  1469.       for (i = 0; i < 256; i++)
  1470.            if (nlextoke[i] == NMC || nlextoke[i] == NMS)
  1471.             char_flags[i] |= CHAR_SIGNIFICANT;
  1472.      }
  1473.  
  1474.      for (i = 0; i < 256; i++)
  1475.       if (char_flags[i] & CHAR_SIGNIFICANT) {
  1476.            /* Significant SGML characters musn't be non-SGML. */
  1477.            if (char_flags[i] & CHAR_NONSGML) {
  1478.             UNCH buf[2];
  1479.             buf[0] = i;
  1480.             buf[1] = '\0';
  1481.             sderr(E_NONSGML, buf, (UNCH *)0);
  1482.             char_flags[i] &= ~CHAR_NONSGML;
  1483.            }
  1484.       }
  1485.       else {
  1486.            /* Shunned characters that are not significant SGML characters
  1487.           must be non-SGML. */
  1488.            if ((char_flags[i] & (CHAR_SHUNNED | CHAR_NONSGML))
  1489.            == CHAR_SHUNNED) {
  1490.            sderr(E_SHUNNED, ltous((long)i), (UNCH *)0);
  1491.            char_flags[i] |= CHAR_NONSGML;
  1492.            }
  1493.       }
  1494.  
  1495.      
  1496.      /* Now munge the lexical tables. */
  1497.      for (p = lextabs; *p; p++) {
  1498.       UNCH nonclass = (*p)[CANON_NONSGML];
  1499.       UNCH datclass = (*p)[CANON_DATACHAR];
  1500.       UNCH nmcclass = (*p)[CANON_NMC];
  1501.       UNCH nmsclass = (*p)[CANON_NMS];
  1502.       UNCH minclass = (*p)[CANON_MIN];
  1503.       for (i = 0; i < 256; i++) {
  1504.            if (char_flags[i] & CHAR_NONSGML) {
  1505.             /* We already know that it's not significant. */
  1506.             if (!(char_flags[i] & CHAR_MAGIC))
  1507.              (*p)[i] = nonclass;
  1508.            }
  1509.            else {
  1510.             if (char_flags[i] & CHAR_MAGIC) {
  1511.              sderr(E_MUSTBENON, ltous((long)i), (UNCH *)0);
  1512.             }
  1513.             else if (!(char_flags[i] & CHAR_SIGNIFICANT))
  1514.              (*p)[i] = datclass;
  1515.             else if (nlextoke
  1516.                  /* This relies on the fact that lextoke
  1517.                 occurs last in lextabs. */
  1518.                  && lextoke[i] != nlextoke[i]) {
  1519.              switch (nlextoke[i]) {
  1520.              case NMC:
  1521.                   (*p)[i] = nmcclass;
  1522.                   break;
  1523.              case NMS:
  1524.                   (*p)[i] = nmsclass;
  1525.                   break;
  1526.              case INV:
  1527.                   /* This will happen if period is not a
  1528.                  name character. */
  1529.                   (*p)[i] = minclass;
  1530.                   break;
  1531.              default:
  1532.                   abort();
  1533.              }
  1534.             }
  1535.            }
  1536.       }
  1537.      }
  1538.      if (nlextran) {
  1539.       memcpy((UNIV)lextran, (UNIV)nlextran, 256);
  1540.       frem((UNIV)nlextran);
  1541.      }
  1542.      if (nlextoke) {
  1543.       frem((UNIV)nlextoke);
  1544.       nlextoke = 0;
  1545.      }
  1546.      
  1547. }
  1548.  
  1549. /* Munge parse tables so that empty start and end tags are not recognized. */
  1550.  
  1551. static VOID noemptytag()
  1552. {
  1553.      static struct parse *pcbs[] = { &pcbconm, &pcbcone, &pcbconr, &pcbconc };
  1554.      int i;
  1555.      
  1556.      for (i = 0; i < SIZEOF(pcbs); i++) {
  1557.       int maxclass, maxstate;
  1558.       int j, k, act;
  1559.       UNCH *plex = pcbs[i]->plex;
  1560.       UNCH **ptab = pcbs[i]->ptab;
  1561.  
  1562.       /* Figure out the maximum lexical class. */
  1563.       maxclass = 0;
  1564.       for (j = 0; j < 256; j++)
  1565.            if (plex[j] > maxclass)
  1566.             maxclass = plex[j];
  1567.  
  1568.       /* Now figure out the maximum state number and at the same time
  1569.          change actions. */
  1570.  
  1571.       maxstate = 0;
  1572.  
  1573.       for (j = 0; j <= maxstate; j += 2) {
  1574.            for (k = 0; k <= maxclass; k++)
  1575.             if (ptab[j][k] > maxstate)
  1576.              maxstate = ptab[j][k];
  1577.            /* If the '>' class has an empty start or end tag action,
  1578.           change it to the action that the NMC class has. */
  1579.            act = ptab[j + 1][plex['>']];
  1580.            if (act == NET_ || act == NST_)
  1581.             ptab[j + 1][plex['>']] = ptab[j + 1][plex['_']];
  1582.       }
  1583.      }
  1584. }
  1585.  
  1586. /* Lookup the value of the entry in pmap PTR whose key is KEY. */
  1587.  
  1588. static UNIV pmaplookup(ptr, key)
  1589. struct pmap *ptr;
  1590. char *key;
  1591. {
  1592.      for (; ptr->name; ptr++)
  1593.       if (strcmp(key, ptr->name) == 0)
  1594.            return ptr->value;
  1595.      return 0;
  1596. }
  1597.  
  1598. /* Return an ASCII representation of N. */
  1599.  
  1600. static UNCH *ltous(n)
  1601. long n;
  1602. {
  1603.      static char buf[sizeof(long)*3 + 2];
  1604.      sprintf(buf, "%ld", n);
  1605.      return (UNCH *)buf;
  1606. }
  1607.  
  1608. VOID sgmlwrsd(fp)
  1609. FILE *fp;
  1610. {
  1611.      int i;
  1612.      int changed;
  1613.      char *p;
  1614.      char uc[256];        /* upper case characters (with different lower
  1615.                    case characters) */
  1616.      char lcletter[256];    /* LC letters: a-z */
  1617.  
  1618.      fprintf(fp, "<!SGML \"%s\"\n", standard);
  1619.      fprintf(fp, "CHARSET\nBASESET \"%s//CHARSET %s//%s\"\nDESCSET\n",
  1620.          SYSTEM_CHARSET_OWNER,
  1621.          SYSTEM_CHARSET_DESCRIPTION,
  1622.          SYSTEM_CHARSET_DESIGNATING_SEQUENCE);
  1623.      
  1624.      if (!done_nonsgml) {
  1625.       done_nonsgml = 1;
  1626.       for (i = 0; i < 256; i++)
  1627.            if ((char_flags[i] & (CHAR_SIGNIFICANT | CHAR_SHUNNED))
  1628.            == CHAR_SHUNNED)
  1629.                 char_flags[i] |= CHAR_NONSGML;
  1630.      }
  1631.      i = 0;
  1632.      while (i < 256) {
  1633.       int j;
  1634.       for (j = i + 1; j < 256; j++)
  1635.            if ((char_flags[j] & CHAR_NONSGML)
  1636.            != (char_flags[i] & CHAR_NONSGML))
  1637.             break;
  1638.       if (char_flags[i] & CHAR_NONSGML)
  1639.            fprintf(fp, "%d %d UNUSED\n", i, j - i);
  1640.       else
  1641.            fprintf(fp, "%d %d %d\n", i, j - i, i);
  1642.       i = j;
  1643.      }
  1644.      fprintf(fp, "CAPACITY\n");
  1645.      changed = 0;
  1646.      for (i = 0; i < NCAPACITY; i++)
  1647.       if (refcapset[i] != sd.capacity[i]) {
  1648.            if (!changed) {
  1649.             fprintf(fp, "SGMLREF\n");
  1650.             changed = 1;
  1651.            }
  1652.            fprintf(fp, "%s %ld\n", captab[i], sd.capacity[i]);
  1653.       }
  1654.      if (!changed)
  1655.       fprintf(fp, "PUBLIC \"%s\"\n", capset_map[0].name);
  1656.      fprintf(fp, "SCOPE DOCUMENT\n");
  1657.      
  1658.      fprintf(fp, "SYNTAX\nSHUNCHAR");
  1659.      for (i = 0; i < 256; i++)
  1660.       if (char_flags[i] & CHAR_SHUNNED)
  1661.            fprintf(fp, " %d", i);
  1662.      fprintf(fp, "\n");
  1663.      fprintf(fp, "BASESET \"%s//CHARSET %s//%s\"\nDESCSET 0 256 0\n",
  1664.          SYSTEM_CHARSET_OWNER,
  1665.          SYSTEM_CHARSET_DESCRIPTION,
  1666.          SYSTEM_CHARSET_DESIGNATING_SEQUENCE);
  1667.  
  1668.      fprintf(fp, "FUNCTION\nRE 13\nRS 10\nSPACE 32\nTAB SEPCHAR 9\n");
  1669.  
  1670.      MEMZERO((UNIV)uc, 256);
  1671.      for (i = 0; i < 256; i++)
  1672.       if (lextran[i] != i)
  1673.            uc[lextran[i]] = 1;
  1674.  
  1675.      MEMZERO((UNIV)lcletter, 256);
  1676.      for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++)
  1677.       lcletter[(unsigned char)*p]= 1;
  1678.  
  1679.      fprintf(fp, "NAMING\n");
  1680.      fputs("LCNMSTRT \"", fp);
  1681.      for (i = 0; i < 256; i++)
  1682.       if (lextoke[i] == NMS && !uc[i] && !lcletter[i])
  1683.            fprintf(fp, "&#%d;", i);
  1684.      fputs("\"\n", fp);
  1685.      fputs("UCNMSTRT \"", fp);
  1686.      for (i = 0; i < 256; i++)
  1687.       if (lextoke[i] == NMS && !uc[i] && !lcletter[i])
  1688.            fprintf(fp, "&#%d;", lextran[i]);
  1689.      fputs("\"\n", fp);
  1690.      fputs("LCNMCHAR \"", fp);
  1691.      for (i = 0; i < 256; i++)
  1692.       if (lextoke[i] == NMC && !uc[i])
  1693.            fprintf(fp, "&#%d;", i);
  1694.      fputs("\"\n", fp);
  1695.      fputs("UCNMCHAR \"", fp);
  1696.      for (i = 0; i < 256; i++)
  1697.       if (lextoke[i] == NMC && !uc[i])
  1698.            fprintf(fp, "&#%d;", lextran[i]);
  1699.      fputs("\"\n", fp);
  1700.  
  1701.      fprintf(fp, "NAMECASE\nGENERAL %s\nENTITY %s\n",
  1702.          sd.namecase[0] ? "YES" : "NO",
  1703.          sd.namecase[1] ? "YES" : "NO");
  1704.      fprintf(fp, "DELIM\nGENERAL SGMLREF\nSHORTREF %s\n",
  1705.          sd.shortref ? "SGMLREF" : "NONE");
  1706.      fprintf(fp, "NAMES SGMLREF\n");
  1707.      if (newkey) {
  1708.       /* The reference key was saved in newkey. */
  1709.       for (i = 0; i < NKEYS; i++)
  1710.            if (newkey[i][0])
  1711.             fprintf(fp, "%s %s\n", newkey[i], key[i]);
  1712.      }
  1713.      fprintf(fp, "QUANTITY SGMLREF\n");
  1714.      if (quantity_changed)
  1715.       for (i = 0; i < NQUANTITY; i++)
  1716.            if (quantity_changed[i])
  1717.             fprintf(fp, "%s %d\n", quantity_names[i], sd.quantity[i]);
  1718.      fprintf(fp,
  1719.          "FEATURES\nMINIMIZE\nDATATAG NO OMITTAG %s RANK NO SHORTTAG %s\n",
  1720.          sd.omittag ? "YES" : "NO",
  1721.          sd.shorttag ? "YES" : "NO");
  1722.      fprintf(fp, "LINK SIMPLE NO IMPLICIT NO EXPLICIT NO\n");
  1723.      fprintf(fp, "OTHER CONCUR NO ");
  1724.      if (sd.subdoc > 0)
  1725.       fprintf(fp, "SUBDOC YES %ld ", sd.subdoc);
  1726.      else
  1727.       fprintf(fp, "SUBDOC NO ");
  1728.      fprintf(fp, "FORMAL %s\n", sd.formal ? "YES" : "NO");
  1729.      fprintf(fp, "APPINFO NONE");
  1730.      fprintf(fp, ">\n");
  1731. }
  1732.  
  1733. /*
  1734. Local Variables:
  1735. c-indent-level: 5
  1736. c-continued-statement-offset: 5
  1737. c-brace-offset: -5
  1738. c-argdecl-indent: 0
  1739. c-label-offset: -5
  1740. End:
  1741. */
  1742.